package control;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import workers.*;
import domain.ConcurrentContainerInterface;
import domain.stack.*;

/**
 * @author igordv
 *
 */
public class Experimentor {

	private static int[] NumberOfWorkers = new int[]{2, 4, 8, 16, 32, 64, 128};
	private static int[] NumberOfOperations = new int[]{1000, 1000000};
	private static int[] SmallNumbers = new int[]{2, 4, 8, 16, 32};//{2, 5, 10, 20, 50, 100, 500};

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//		oneProducersOneConsumer(new ConcurrentStack<Integer>());
		//		twoProducersOneConsumer(new ConcurrentStack<Integer>());
		//		oneProducersOneConsumer(new IlConcurrentStack<Integer>(5));
		//		twoProducersOneConsumer(new IlConcurrentStack<Integer>(5));
		//		oneProducersOneConsumer(new ConcurrentStack<Integer>());
		//		twoProducersOneConsumer(new ConcurrentStack<Integer>());

		try {
			performanceExperiment();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//		TraiberTries();
		//		stackSimilarityExperiment();
	}

	private static void TraiberTries() {
		for (int j = 0; j < NumberOfWorkers.length; j++) {
			int numberOfProducers = NumberOfWorkers[j]-1;
			int numberOfInsertions = 1000000/2;
			int insrtionsPerWorker = numberOfInsertions/numberOfProducers;
			int realInsertions = numberOfProducers*insrtionsPerWorker;

			ConcurrentStack<Integer> concurrentStack = new ConcurrentStack<Integer>();
			long currentTimeMillis = System.currentTimeMillis();
			for (int m = 0; m < numberOfProducers; m++) {
				new Thread(new PositiveProducer(concurrentStack, insrtionsPerWorker)).start();
			}
			Thread consumer = new Thread (new Consumer(concurrentStack, realInsertions-1));
			consumer.start();
			try {
				consumer.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String out = "numberOfWorkoers , "+(numberOfProducers+1)+
			" , numberOfOperations , "+1000000+
			" , SmallNumbers , "+"--"+
			" , time in millis , "+(System.currentTimeMillis()-currentTimeMillis);

			System.out.println(" averege CAS: " +(sum));
			sum=0;
			System.out.println(out);

		}


	}

	public static int sum = 0;

	public static void performanceExperiment() throws IOException{
		BufferedWriter writer = new BufferedWriter(new FileWriter(new File("stack_performance_experiment_(on dt-s2 server) IlConcurrentStack_v2_insert in random place.txt")));
		for (int i = 0; i < NumberOfOperations.length; i++) {
			for (int j = 0; j < NumberOfWorkers.length; j++) {
				int numberOfProducers = NumberOfWorkers[j]-1;
				int numberOfInsertions = NumberOfOperations[i]/2;
				int insrtionsPerWorker = numberOfInsertions/numberOfProducers;
				int realInsertions = numberOfProducers*insrtionsPerWorker;

//				for (int k = 0; k < SmallNumbers.length; k++) {
//					int smallNumber = SmallNumbers[k];
					IlConcurrentStack_v2<Integer> ilConcurrentStack = new IlConcurrentStack_v2<Integer>(numberOfProducers/5);
					long currentTimeMillis = System.currentTimeMillis();
					for (int m = 0; m < numberOfProducers; m++) {
						new Thread(new PositiveProducer(ilConcurrentStack,insrtionsPerWorker, 10)).start(); // TODO 
					}
					Thread consumer = new Thread (new Consumer(ilConcurrentStack,realInsertions-1, 10));// TODO
					consumer.start();
					try {
						consumer.join();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					String out = "numberOfWorkers , "+(numberOfProducers+1)+
					" , numberOfOperations , "+NumberOfOperations[i]+
					" , SmallNumbers , "+(numberOfProducers/5)+
					" , time in millis , "+(System.currentTimeMillis()-currentTimeMillis);
					writer.write(out+"\n");
					writer.flush();
					System.out.println(out);
//				}

				ConcurrentStack<Integer> concurrentStack = new ConcurrentStack<Integer>();
				currentTimeMillis = System.currentTimeMillis();
				for (int m = 0; m < numberOfProducers; m++) {
					new Thread(new PositiveProducer(concurrentStack, insrtionsPerWorker, 10)).start();// TODO
				}
				consumer = new Thread (new Consumer(concurrentStack, realInsertions-1, 10));// TODO
				consumer.start();
				try {
					consumer.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				out = "numberOfWorkoers , "+(numberOfProducers+1)+
				" , numberOfOperations , "+NumberOfOperations[i]+
				" , SmallNumbers , "+"--"+
				" , time in millis , "+(System.currentTimeMillis()-currentTimeMillis);
				writer.write(out+"\n");
				writer.flush();
				System.out.println(out);

			}
		}

		writer.close();
	}

	@SuppressWarnings("unused")
	private static void oneProducersOneConsumer(ConcurrentContainerInterface<Integer> concurrentStack) {
		new Thread(new PositiveProducer(concurrentStack,50,4000)).start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread (new Consumer(concurrentStack,50)).start();
	}

	@SuppressWarnings("unused")
	private static void twoProducersOneConsumer(ConcurrentContainerInterface<Integer> concurrentStack) {
		long currentTimeMillis = System.currentTimeMillis();
		System.out.println(currentTimeMillis);
		Thread p1 = new Thread(new PositiveProducer(concurrentStack,10000));
		p1.start();
		Thread p2 = new Thread(new NegativeProducer(concurrentStack,10000));
		p2.start();

		//		try {
		//		Thread.sleep(2000);
		//		} catch (InterruptedException e) {
		//		e.printStackTrace();
		//		}
		try {
			p1.join();
			p2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}



		Thread c = new Thread (new Consumer(concurrentStack,19999));
		c.start();
		try {
			c.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long currentTimeMillis2 = System.currentTimeMillis();

		System.out.println(currentTimeMillis2);
		System.out.println(currentTimeMillis2-currentTimeMillis);
	}

	private static void stackSimilarityExperiment() {
		IlConcurrentStack<Integer> ilConcurrentStack = new IlConcurrentStack<Integer>(0);
		ConcurrentStack<Integer> concurrentStack = new ConcurrentStack<Integer>();
		long timeCounter=0;

		for (int i = 0; i < 10; i++) {
			long currentTimeMillis = System.currentTimeMillis();
			for (int m = 0; m < 10; m++) {
				new Thread(new PositiveProducer(ilConcurrentStack,100000)).start();
			}
			Thread consumer = new Thread (new Consumer(ilConcurrentStack,999999));
			consumer.start();
			try {
				consumer.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			timeCounter += System.currentTimeMillis()-currentTimeMillis;
		}
		System.out.println("mean (from 10 tries) time for insertion of 1M elements " +
				"by 10 processes To IlConcurrentStack<Integer>(0) is: "+ (timeCounter/10));
		timeCounter=0;
		for (int i = 0; i < 10; i++) {
			long currentTimeMillis = System.currentTimeMillis();
			for (int m = 0; m < 10; m++) {
				new Thread(new PositiveProducer(concurrentStack,100000)).start();
			}
			Thread consumer = new Thread (new Consumer(concurrentStack,999999));
			consumer.start();
			try {
				consumer.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			timeCounter += System.currentTimeMillis()-currentTimeMillis;
		}
		System.out.println("mean (from 10 tries) time for insertion of 1M elements " +
				"by 10 processes To IlConcurrentStack<Integer>(0) is: "+ (timeCounter/10));

		// stackSimilarityExperiment
		// mean (from 10 tries) time for insertion of 1M elements by 10 processes To IlConcurrentStack<Integer>(0) is: 6485
		// mean (from 10 tries) time for insertion of 1M elements by 10 processes To IlConcurrentStack<Integer>(0) is: 6106
		//
	}
}
